package frames;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.sql.Connection;
import java.sql.SQLException;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.filechooser.FileNameExtensionFilter;

import parameters.ConnectionParams;

/** Implements a frame which will be used
 * for establishing a connection to a database
 * and saving a file with the connection data
 * 
 * @author Konstantin Dobrev
 * @version 1.0
 */
class ConnectionFrame extends JFrame {

	private static final long serialVersionUID = 1L;
	private Panel pane;
	private JTextField username;
	private JTextField port;
	private JPasswordField password;
	private JComboBox database;
	private JCheckBox passwordCheck;
	private JButton saveConn;
	private JButton connect;
	private ConnectionParams connParameters;
	private ProgramMenuBar menuReff;
	
	/** Constructor for this class
	 * 
	 * @param pars contains connection data like username, 
	 * password and port for the daatabase
	 * 
	 * @param caller contains a reference to the menu
	 * from which the instance is being created. It is 
	 * used to set some global settings of the application
	 */
	ConnectionFrame(ConnectionParams pars, ProgramMenuBar caller) {
		super("Connection");
		connParameters = pars;
		menuReff = caller;
		this.setSize(350, 360);
		this.setVisible(true);
		this.setResizable(false);
		this.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
		
		pane = new Panel(new GridBagLayout());
		this.add(pane);
		GridBagConstraints position = new GridBagConstraints();
		position.anchor = GridBagConstraints.FIRST_LINE_START;
		
		JLabel dbLabel = new JLabel("Database type:");
		position.insets = new Insets(0, 0, 0, 0);
		position.gridx = 0;
		position.gridy = 0;
		pane.add(dbLabel, position);
		
		String [] dbTypes = { "MySQL", "MS SQLServer" };
		database = new JComboBox(dbTypes);
		position.insets = new Insets(0, 18, 4, 0);
		position.gridx = 1;
		position.gridy = 0;
		pane.add(database, position);
		
		JLabel portLabel = new JLabel("Port:");
		position.insets = new Insets(0, 0, 0, 0);
		position.gridx = 0;
		position.gridy = 1;
		pane.add(portLabel, position);
		
		port = new JTextField(6);
		position.insets = new Insets(0, 18, 4, 0);
		position.gridx = 1;
		position.gridy = 1;
		pane.add(port, position);
		
		JLabel userLabel = new JLabel("Username:");
		position.insets = new Insets(0, 0, 0, 0);
		position.gridx = 0;
		position.gridy = 2;
		pane.add(userLabel, position);
		
		username = new JTextField(12);
		position.insets = new Insets(0, 18, 4, 0);
		position.gridx = 1;
		position.gridy = 2;
		pane.add(username, position);
		
		JLabel passLabel = new JLabel("Password:");
		position.insets = new Insets(0, 0, 0, 0);
		position.gridx = 0;
		position.gridy = 3;
		pane.add(passLabel, position);
		
		password = new JPasswordField(12);
		position.insets = new Insets(0, 18, 9, 0);
		position.gridx = 1;
		position.gridy = 3;
		pane.add(password, position);
		
		JLabel passCheckLabel = new JLabel("Save password?");
		position.insets = new Insets(0, 0, 0, 0);
		position.gridx = 0;
		position.gridy = 4;
		pane.add(passCheckLabel, position);
		
		passwordCheck = new JCheckBox();
		position.insets = new Insets(0, 18, 24, 0);
		position.gridx = 1;
		position.gridy = 4;
		pane.add(passwordCheck, position);
		
		connect = new JButton("Connect");
		connect.addActionListener(new ConnectionHandler(1, this));
		position.insets = new Insets(0, 9, 0, 0);
		position.gridx = 0;
		position.gridy = 5;
		pane.add(connect, position);
		
		saveConn = new JButton("Save connection file");
		saveConn.addActionListener(new ConnectionHandler(2, this));
		position.insets = new Insets(0, 0, 0, 0);
		position.gridx = 1;
		position.gridy = 5;
		pane.add(saveConn, position);
	}
	
	
	/**
	 * Sets the frame's fields with the data 
	 * from the {@link connParameters} referemce
	 * @see ConnectionParams
	 */
	public void setFields() {
		port.setText(connParameters.getPort());
		username.setText(connParameters.getUsername());
		password.setText(connParameters.getPassword());
		passwordCheck.setSelected(connParameters.isPassSaved());
	}
	
	/** Implements an action listener. It reacts to
	 * the pressing of {@link connect} and {@link saveConn} buttons
	 * @author Konstantin Dobrev
	 * @version 1.0
	 */
	private class ConnectionHandler implements ActionListener {
		
		private int action;
		ConnectionFrame caller;
		
		/** Constructor for this class
		 * 
		 * @param num contains the value which determines what action
		 * will be invoked for the button
		 * @param connFr contains a reference to the container class
		 * which is used for visualization purposes after establishing a connection
		 */
		ConnectionHandler(int num, ConnectionFrame connFr) {
			action = num;
			caller = connFr;
		}

		@Override
		public void actionPerformed(ActionEvent arg0) {
			// TODO Auto-generated method stub
			switch(action) {
			case 1: connect(); break;
			case 2: saveFile();
			}
		}
		
		/** Establishes a connection to a database based on the
		 *  data filled by the user in the frame
		 *  
		 *  @exception SQLException
		 */
		private void connect() {
			if(connParameters.getConnectionName() == null) {
				connParameters.setPort(port.getText());
				switch(database.getSelectedIndex()) {
					case 0: connParameters.setDbType("mysql"); break;
					case 1: connParameters.setDbType("sqlserver");
				}
				connParameters.setUsername(username.getText());
				connParameters.setPassword(new String (password.getPassword()));
			}
			Connection resultConn = null;
			try {
				resultConn = connParameters.createConnection();
				JOptionPane.showMessageDialog(null, "Connection established!");
				menuReff.getMainRefference().getDbTree().setConnDatabases(resultConn);
				menuReff.setConnectionClosing(true);
				menuReff.getMainRefference().setVisible(true);
				menuReff.setConnection(resultConn);
				caller.setVisible(true);
			}
			catch(SQLException ex) {
				JOptionPane.showMessageDialog(null, ex.getMessage());
			}
		}
		
		
		/** Saves a .cmng file to the filesystem which contains 
		 * filled data from the frame
		 * 
		 * @exception FileNotFoundException
		 * @exception IOException
		 */
		private void saveFile() {
			connParameters.setUsername(username.getText());
			switch(database.getSelectedIndex()) {
				case 0: connParameters.setDbType("mysql"); break;
				case 1: connParameters.setDbType("sqlserver");
			}
			connParameters.setPort(port.getText());
			String passAfterCheck = passwordCheck.isSelected() ? (new String(password.getPassword())) : "";
			connParameters.setPassword(passAfterCheck);
			JFileChooser chooser = new JFileChooser();
			FileNameExtensionFilter filter = new FileNameExtensionFilter("Connection manager files", "cmng");
			chooser.setFileFilter(filter);
			int saved = chooser.showSaveDialog(pane);
			if(saved == 0) {
				String fileName = chooser.getSelectedFile().getPath();
				String resultName = fileName.endsWith(".cmng") ? fileName : fileName + ".cmng";
				File selectedFile = new File(resultName);
				FileOutputStream saveStream = null;
				ObjectOutputStream objectStream = null;
				try {
					saveStream = new FileOutputStream(selectedFile);
					objectStream = new ObjectOutputStream(saveStream);
					objectStream.writeObject(connParameters);
					
					objectStream.close();
					saveStream.close();
				}
				catch (FileNotFoundException ex) {
					JOptionPane.showMessageDialog(null, ex.getMessage());
				}
				catch(IOException ex) {
					JOptionPane.showMessageDialog(null, ex.getMessage());
				}
			}
		}
		
	}
	
}
